package com.jushu.storbox.manager;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

import com.jushu.storbox.R;
import com.jushu.storbox.ShareDriveApplication;
import com.jushu.storbox.callback.ITCallback;
import com.jushu.storbox.constant.Constant;
import com.jushu.storbox.database.DAOFactory;
import com.jushu.storbox.database.IAlbumDao;
import com.jushu.storbox.database.IAlbumFolderDao;
import com.jushu.storbox.database.IUserDao;
import com.jushu.storbox.entities.AlbumFileInfo;
import com.jushu.storbox.entities.AlbumFolderInfo;
import com.jushu.storbox.entities.UploadObject;
import com.jushu.storbox.entities.User;
import com.jushu.storbox.filter.MadieFilter;
import com.jushu.storbox.handler.ClientExceptionRelateHandler;
import com.jushu.storbox.task.tqueue.AlbumUploadTask;
import com.jushu.storbox.util.LogUtil;
import com.jushu.storbox.util.PublicTools;
import com.huawei.sharedrive.sdk.android.exception.ClientException;
import com.huawei.sharedrive.sdk.android.model.request.FolderBaseRequest;
import com.huawei.sharedrive.sdk.android.model.request.FolderCreateRequest;
import com.huawei.sharedrive.sdk.android.modelV2.request.FolderListRequestV2;
import com.huawei.sharedrive.sdk.android.modelV2.request.FolderMoveRequstV2;
import com.huawei.sharedrive.sdk.android.modelV2.request.Order;
import com.huawei.sharedrive.sdk.android.modelV2.response.FileInfoResponseV2;
import com.huawei.sharedrive.sdk.android.modelV2.response.FolderListResponseV2;
import com.huawei.sharedrive.sdk.android.modelV2.response.FolderResponse;
import com.huawei.sharedrive.sdk.android.serviceV2.FolderClientV2;
import com.huawei.sharedrive.sdk.android.util.StringUtil;

public class AlbumBackManager {

	protected static final String TAG = AlbumBackManager.class.getSimpleName();

	protected static final int BACKUP_COUNT_ONCE = 10;

	private static final int ALBUM_BACKUP_ERVER_MILLIS = 5 * 60 * 1000;

	private static AlbumBackManager manager = null;
	private Context context;
	private Timer backupTimer = null;
	String deviceName = "";
	String albumFolderName = "";
	String albumFolderId = "";
	boolean isRequestStopBackup = false;
	FolderResponse myDeviceFolder = null;
	FolderResponse myAlbumFolder = null;
	String ownerId = "";
	User user = null;
	StateWrappter state = new StateWrappter();
	MadieFilter filter = new MadieFilter();

	private AlbumBackUpTimerTask albumBackupTimerTask = null;

	private ITCallback<UploadObject, FileInfoResponseV2> iCallback = new ITCallback<UploadObject, FileInfoResponseV2>() {
		public void onStart(UploadObject request) {
		}

		public void onFailure(UploadObject request, Throwable t) {

			updateStatusAndStartNewBackupItem(request, IAlbumDao.ALBUM_STATUS_FAILURE);
		}

		public void onSuccess(UploadObject request, FileInfoResponseV2 successItem) {

			updateStatusAndStartNewBackupItem(request, IAlbumDao.ALBUM_STATUS_SUCCESS);
		}

		public void onProgress(UploadObject request, int currentProgress, long currentSize, long maxSize) {
			if (request != null) {
				IAlbumDao albumDao = DAOFactory.instance(context).getAlbumDao();
				AlbumFileInfo albumFile = albumDao.getFileByPath(request.getLoctPath());
				if (albumFile != null) {
					albumDao.updateAlbumState(albumFile);
				}
			}
		}

		private void updateStatusAndStartNewBackupItem(UploadObject request, int status) {

			if (isRequestStopBackup) {
				return;
			}

			if (request != null) {
				IAlbumDao albumDao = DAOFactory.instance(context).getAlbumDao();
				AlbumFileInfo albumFile = albumDao.getFileByPath(request.getLoctPath());
				if (albumFile != null) {
					albumFile.setStatus(status);
					albumDao.updateAlbumState(albumFile);
				}
			}

			if (user == null && user.getAlbumAutoBackup() == IUserDao.ALBUM_AUTO_BACKUP_FALSE) {
				return;
			}

			if (!PublicTools.isAuthiorzationGotoTimeout(context)) {
				IAlbumDao albumDao = DAOFactory.instance(context).getAlbumDao();
				List<AlbumFileInfo> albumFiles = albumDao.getNotBackedFileList();
				if (!albumFiles.isEmpty()) {
					IAlbumFolderDao albumFolderDao = DAOFactory.instance(context).getAlbumFolderDao();
					AlbumFileInfo albumFile = albumFiles.get(0);
					AlbumFolderInfo backFolder = albumFolderDao.getAlbumFolder(ownerId, albumFile.getParent());

					FolderResponse tempAlbumFolder = getAlbumFolderFromServer(backFolder.getServerFolderId());
					if (tempAlbumFolder != null) {
						AlbumUploadTask uploadTask = new AlbumUploadTask(context, ownerId, backFolder.getServerFolderId(), albumFile.getFilePath(), iCallback);
						AlbumUploadTaskManager.instance().addTask(uploadTask);
					}
				}
			}
		}
	};

	private class AlbumBackUpTimerTask extends TimerTask {

		@Override
		public void run() {

			try {
				user = ShareDriveApplication.getInstance().getCurrentUser();
				if (user == null) {
					return;
				}
				if (user.getAlbumEnabled() != IUserDao.ALBUM_ENABLED_TRUE || user.getAlbumAutoBackup() != IUserDao.ALBUM_AUTO_BACKUP_TRUE) {
					return;
				}
				NetworkInfo network = ShareDriveApplication.getInstance().getWifiController().getNetworkInfo();

				if (!network.isAvailable()) {
					return;
				}

				if (user.getBackupAlbumOnlyWifi() == IUserDao.ALBUM_BACKUP_ONLYWIFI_TRUE && network.getType() == ConnectivityManager.TYPE_WIFI) {

				} else {

				}
				if (user.getBackupAlbumOnlyWifi() == IUserDao.ALBUM_BACKUP_ONLYWIFI_TRUE) {
					if (network.getType() != ConnectivityManager.TYPE_WIFI) {
						return;
					} else {
						doTask();
					}
				} else { // pop a promit dialog ?
					doTask();
				}
			} catch (ClientException e) {
				LogUtil.e(TAG, e.getMessage());
			} catch (Exception e) {
				LogUtil.e(TAG, e.getMessage());
			}

		}

		private void doTask() throws ClientException {
			long avaliedTime = PublicTools.getAvaliedTimeMillis(context);
			if (avaliedTime < ALBUM_BACKUP_ERVER_MILLIS) {
				PublicTools.reGetTokenByLoginInBanck(context);
			}

			myDeviceFolder = null;
			myAlbumFolder = null;
			albumFolderId = "";
			isRequestStopBackup = false;
			ownerId = user.getUserId();
			albumFolderName = context.getString(R.string.camera_folder_name);
			albumFolderId = user.getAlbumFolderId();
			deviceName = new DeviceInfoManager(context).getDeviceInfo().getDeviceSN();

			myAlbumFolder = getAlbumFolderFromServer(albumFolderId);
			if (isRequestStopBackup) {
				return;
			}
			if (myAlbumFolder == null) {
				myAlbumFolder = makeSureTargetFolderExists(ownerId, Constant.ROOT_FOLDER_ID, albumFolderName);
				updateAlbumFolderIdToUserInfo(myAlbumFolder);
			}
			if (myAlbumFolder != null) {
				myDeviceFolder = makeSureTargetFolderExists(ownerId, myAlbumFolder.getId(), deviceName);
			}
			if (isRequestStopBackup) {
				return;
			}
			if (myDeviceFolder != null) {
				IAlbumFolderDao albumFolderDao = DAOFactory.instance(context).getAlbumFolderDao();
				// make sure the backup folder exists
				List<AlbumFolderInfo> albumFolderList = backupFolderStruct(albumFolderDao);
				if (isRequestStopBackup) {
					return;
				}
				scanBackupFolderChange(albumFolderList);

				if (isRequestStopBackup) {
					return;
				}
				// backup the file
				backupFiles(albumFolderDao, albumFolderList);

			} else {
				LogUtil.e(TAG, "no get available album folder");
			}
		}

		private void scanBackupFolderChange(List<AlbumFolderInfo> albumFolders) {
			if (albumFolders == null) {
				return;
			}
			IAlbumDao albumDao = DAOFactory.instance(context).getAlbumDao();
			for (AlbumFolderInfo folder : albumFolders) {
				String folderPath = folder.getFolderPath();
				File folderFile = new File(folderPath);
				if (folderFile.exists()) {
					File[] fileArr = folderFile.listFiles(filter);
					if (fileArr != null) {
						for (File f : fileArr) {
							if (f.getName().startsWith(".")) {// filter the hide
																// file
								continue;
							}
							long fileLenght = f.length();
							if (fileLenght > 0 && fileLenght <= Constant.ONE_GB && albumDao.getFileByPath(f.getAbsolutePath()) == null) {
								AlbumFileInfo albumFileInfo = new AlbumFileInfo();
								albumFileInfo.setFileName(f.getName());
								albumFileInfo.setFilePath(f.getAbsolutePath());
								albumFileInfo.setFileSize(f.length());
								albumFileInfo.setClientMtime(f.lastModified());
								albumFileInfo.setParent(folderPath);
								albumFileInfo.setOwnerBy(ownerId);
								albumFileInfo.setStatus(IAlbumDao.ALBUM_STATUS_NEWFILE);
								albumDao.insertFile(albumFileInfo);
							}
						}
					}
				}
			}
		}

		private void updateAlbumFolderIdToUserInfo(FolderResponse myAlbumFolder) {
			if (myAlbumFolder != null && user != null) {
				user.setAlbumFolderId(myAlbumFolder.getId());
				DAOFactory.instance(context).getUserDao().updateAlbumFolderId(user);
			}
		}

		private void backupFiles(IAlbumFolderDao albumFolderDao, List<AlbumFolderInfo> albumFolderList) {
			Set<AlbumUploadTask> uploadTasks = AlbumUploadTaskManager.instance().getAllTaskes();
			if (uploadTasks.isEmpty()) {
				IAlbumDao albumDao = DAOFactory.instance(context).getAlbumDao();
				List<AlbumFileInfo> albumFiles = albumDao.getNotBackedFileList();
				if (!albumFiles.isEmpty()) {
					AlbumFileInfo albumFile = albumFiles.get(0);
					AlbumFolderInfo backFolder = albumFolderDao.getAlbumFolder(ownerId, albumFile.getParent());
					AlbumUploadTask uploadTask = new AlbumUploadTask(context, ownerId, backFolder.getServerFolderId(), albumFile.getFilePath(), iCallback);
					AlbumUploadTaskManager.instance().addTask(uploadTask);
				}
			}
		}

		private List<AlbumFolderInfo> backupFolderStruct(IAlbumFolderDao albumFolderDao) throws ClientException {
			List<AlbumFolderInfo> albumFolderList = albumFolderDao.getAlbumFolders(ownerId);
			for (AlbumFolderInfo folder : albumFolderList) {
				FolderResponse tempAlbumFolder = getAlbumFolderFromServer(folder.getServerFolderId());
				if (tempAlbumFolder == null || !myDeviceFolder.getId().equals(tempAlbumFolder.getParent())) {
					// is first user this function or delete or move to other
					// space and then create folder
					if (new File(folder.getFolderPath()).exists()) {
						FolderResponse albumFolder = makeSureTargetFolderExists(ownerId, myDeviceFolder.getId(), folder);
						// update the folder id to database
						folder.setServerFolderId(albumFolder.getId());
						albumFolderDao.updateAlumbFolderInfo(folder);
					} else {// delete from database and not delete from list
						albumFolderDao.deleteAlumbFolderInfo(folder);
						folder.setState(AlbumFolderInfo.FOLDER_STATE_DELETE);// delete
																				// flag
					}
				}
			}
			return albumFolderList;
		}

		private FolderResponse makeSureTargetFolderExists(String ownerId, String folderId, AlbumFolderInfo albumFolder) throws ClientException {
			List<Order> orderList = new ArrayList<Order>();
			orderList.add(new Order("type", "ASC"));

			FolderListRequestV2 request = new FolderListRequestV2();
			request.setFolderID(folderId);
			request.setLimit(1000);
			request.setOffset(0);
			request.setOwnerID(ownerId);
			request.setOrder(orderList);
			FolderListResponseV2 folderList = FolderClientV2.getInstance().getFolderInfoList(request, ShareDriveApplication.getInstance().getAuthorization());

			FolderResponse serverAlbumFolder = null;
			List<FolderResponse> folders = folderList.getFolders();
			for (FolderResponse serverFolder : folders) {

				// set regularExpression
				String re = "(" + albumFolder.getFolderName() + ")" + "(\\(\\d{1,}\\)){0,}";

				if (albumFolder.getFolderName().matches(re)) {
					// same name

					if (StringUtil.isBlank(albumFolder.getServerFolderId())) {
						// no id
						if (serverFolder.getContentCreatedAt() == albumFolder.getContentCreateAt()) {
							serverAlbumFolder = serverFolder;

						} else {
							continue;
						}
					} else {
						if (serverFolder.getId().equals(albumFolder.getServerFolderId())) {
							// same name and same id
							serverAlbumFolder = serverFolder;
						} else {
							// same name only
							continue;
						}
					}

					break;
				}
			}

			if (serverAlbumFolder == null) {
				serverAlbumFolder = createFolder(folderId, albumFolder);
			}

			return serverAlbumFolder;
		}

		private FolderResponse makeSureTargetFolderExists(String ownerId, String folderId, String folderName) throws ClientException {
			List<Order> orderList = new ArrayList<Order>();
			orderList.add(new Order("type", "ASC"));

			FolderListRequestV2 request = new FolderListRequestV2();
			request.setFolderID(folderId);
			request.setLimit(1000);
			request.setOffset(0);
			request.setOwnerID(ownerId);
			request.setOrder(orderList);
			FolderListResponseV2 folderList = FolderClientV2.getInstance().getFolderInfoList(request, ShareDriveApplication.getInstance().getAuthorization());

			FolderResponse albumFolder = null;
			List<FolderResponse> folders = folderList.getFolders();
			for (FolderResponse serverFolder : folders) {
				if (serverFolder.getName().equals(folderName)) {

					albumFolder = serverFolder;
					break;
				}
			}
			if (albumFolder == null) {
				albumFolder = createFolder(folderId, folderName);
			}

			return albumFolder;
		}

		private FolderResponse createFolder(String parentId, String folderName) throws ClientException {
			FolderCreateRequest createReq = new FolderCreateRequest();
			createReq.setName(folderName);
			createReq.setParent(parentId);
			return FolderClientV2.getInstance().create(ownerId, createReq, ShareDriveApplication.getInstance().getAuthorization());
		}

		private FolderResponse createFolder(String parentId, AlbumFolderInfo albumFolder) throws ClientException {
			String tempFolderId = "";
			if (myAlbumFolder != null) {
				tempFolderId = myAlbumFolder.getId();
			}
			FolderResponse targetFolder = null;
			// create folder in myalbum
			FolderCreateRequest createReq = new FolderCreateRequest();
			createReq.setName(albumFolder.getFolderName());
			createReq.setParent(tempFolderId);
			createReq.setContentCreatedAt(albumFolder.getContentCreateAt());
			FolderResponse tempFolder = FolderClientV2.getInstance().create(ownerId, createReq, ShareDriveApplication.getInstance().getAuthorization());
			try {
				// move to device folder
				FolderMoveRequstV2 request = new FolderMoveRequstV2();
				request.setDestParent(parentId);
				request.setAutoRename(true);
				request.setDestOwnerId(ownerId);
				targetFolder = FolderClientV2.getInstance().moveFolder(tempFolder.getOwnedBy(), tempFolder.getId(),
						ShareDriveApplication.getInstance().getAuthorization(), request);
			} catch (ClientException e) {
				if (e.getStatusCode() == ClientExceptionRelateHandler.ERROR_CODE_404_NO_RESOURCE && tempFolder != null) {
					FolderBaseRequest delteReq = new FolderBaseRequest();
					delteReq.setOwnerID(ownerId);
					delteReq.setFolderID(tempFolder.getId());
					delteReq.setAuthorization(ShareDriveApplication.getInstance().getAuthorization());
					FolderClientV2.getInstance().deleteFolder(delteReq);
				}
				throw e;
			}
			return targetFolder;
		}
	};

	private FolderResponse getAlbumFolderFromServer(String folderId) {
		if (StringUtil.isBlank(folderId)) {
			return null;
		}
		FolderBaseRequest folderRequest = new FolderBaseRequest();
		folderRequest.setOwnerID(ownerId);
		folderRequest.setFolderID(folderId);
		folderRequest.setAuthorization(ShareDriveApplication.getInstance().getAuthorization());
		FolderResponse serverFolder = null;
		try {
			serverFolder = FolderClientV2.getInstance().getFolderInfo(folderRequest);
		} catch (ClientException e) {
		}
		return serverFolder;
	}

	private AlbumBackManager(Context context) {
		this.context = context;
	}

	public static AlbumBackManager instance(Context context) {
		if (manager == null) {
			manager = new AlbumBackManager(context);
		}
		return manager;
	}

	public void startAlbumBackup() {
		synchronized (state) {
			if (!state.isTaskIsRunning()) {
				if (backupTimer == null) {
					backupTimer = new Timer();
				}
				isRequestStopBackup = false;

				if (albumBackupTimerTask == null) {
					albumBackupTimerTask = new AlbumBackUpTimerTask();
				}
				if (backupTimer != null && albumBackupTimerTask != null) {
					backupTimer.schedule(albumBackupTimerTask, 3000, ALBUM_BACKUP_ERVER_MILLIS);
				}
				state.setTaskIsRunning(true);
			}
		}
	}

	public void stopAlbumBackup() {
		if (backupTimer != null) {
			backupTimer.cancel();
			backupTimer = null;
		}
		isRequestStopBackup = true;
		if (albumBackupTimerTask != null) {
			albumBackupTimerTask.cancel();
			albumBackupTimerTask = null;
		}
		synchronized (state) {
			state.setTaskIsRunning(false);
		}

		AlbumUploadTaskManager.instance().stopAllTasks();
	}

	class StateWrappter {
		private boolean taskIsRunning = false;

		public boolean isTaskIsRunning() {
			return taskIsRunning;
		}

		public void setTaskIsRunning(boolean taskIsRunning) {
			this.taskIsRunning = taskIsRunning;
		}
	}
}
